// JWT认证工具
import jwt from 'jsonwebtoken'
import { prisma } from './prisma'
import { CacheManager } from './memory-cache'

interface JWTPayload {
  userId: string
  email: string
  iat?: number
  exp?: number
}

interface TokenPair {
  accessToken: string
  refreshToken: string
}

export class JWTManager {
  private static readonly ACCESS_TOKEN_SECRET = process.env.JWT_ACCESS_SECRET || 'your-access-secret'
  private static readonly REFRESH_TOKEN_SECRET = process.env.JWT_REFRESH_SECRET || 'your-refresh-secret'
  private static readonly ACCESS_TOKEN_EXPIRES = '15m' // 15分钟
  private static readonly REFRESH_TOKEN_EXPIRES = '7d' // 7天

  // 生成访问令牌
  static generateAccessToken(payload: Omit<JWTPayload, 'iat' | 'exp'>): string {
    return jwt.sign(payload, this.ACCESS_TOKEN_SECRET, {
      expiresIn: this.ACCESS_TOKEN_EXPIRES,
      issuer: 'search-dashboard',
      audience: 'search-dashboard-client'
    })
  }

  // 生成刷新令牌
  static generateRefreshToken(payload: Omit<JWTPayload, 'iat' | 'exp'>): string {
    return jwt.sign(payload, this.REFRESH_TOKEN_SECRET, {
      expiresIn: this.REFRESH_TOKEN_EXPIRES,
      issuer: 'search-dashboard',
      audience: 'search-dashboard-client'
    })
  }

  // 生成令牌对
  static generateTokenPair(payload: Omit<JWTPayload, 'iat' | 'exp'>): TokenPair {
    return {
      accessToken: this.generateAccessToken(payload),
      refreshToken: this.generateRefreshToken(payload)
    }
  }

  // 验证访问令牌
  static verifyAccessToken(token: string): JWTPayload | null {
    try {
      return jwt.verify(token, this.ACCESS_TOKEN_SECRET, {
        issuer: 'search-dashboard',
        audience: 'search-dashboard-client'
      }) as JWTPayload
    } catch (error) {
      return null
    }
  }

  // 验证刷新令牌
  static verifyRefreshToken(token: string): JWTPayload | null {
    try {
      return jwt.verify(token, this.REFRESH_TOKEN_SECRET, {
        issuer: 'search-dashboard',
        audience: 'search-dashboard-client'
      }) as JWTPayload
    } catch (error) {
      return null
    }
  }

  // 解码令牌（不验证）
  static decodeToken(token: string): JWTPayload | null {
    try {
      return jwt.decode(token) as JWTPayload
    } catch (error) {
      return null
    }
  }

  // 将刷新令牌存储到数据库
  static async storeRefreshToken(userId: string, refreshToken: string): Promise<void> {
    try {
      const decoded = this.decodeToken(refreshToken)
      if (!decoded || !decoded.exp) return

      const tokenHash = this.hashToken(refreshToken)
      const expiresAt = new Date(decoded.exp * 1000)

      await prisma.userSession.create({
        data: {
          userId,
          tokenHash,
          expiresAt
        }
      })
    } catch (error) {
      console.error('存储刷新令牌失败:', error)
    }
  }

  // 验证刷新令牌是否在数据库中
  static async validateRefreshToken(refreshToken: string): Promise<boolean> {
    try {
      const tokenHash = this.hashToken(refreshToken)
      const session = await prisma.userSession.findFirst({
        where: {
          tokenHash,
          expiresAt: {
            gt: new Date()
          }
        }
      })
      return !!session
    } catch (error) {
      console.error('验证刷新令牌失败:', error)
      return false
    }
  }

  // 撤销刷新令牌
  static async revokeRefreshToken(refreshToken: string): Promise<void> {
    try {
      const tokenHash = this.hashToken(refreshToken)
      await prisma.userSession.deleteMany({
        where: {
          tokenHash
        }
      })
    } catch (error) {
      console.error('撤销刷新令牌失败:', error)
    }
  }

  // 撤销用户的所有刷新令牌
  static async revokeAllUserTokens(userId: string): Promise<void> {
    try {
      await prisma.userSession.deleteMany({
        where: {
          userId
        }
      })
      
      // 清理用户缓存
      await CacheManager.clearUserCache(userId)
    } catch (error) {
      console.error('撤销用户所有令牌失败:', error)
    }
  }

  // 清理过期的会话
  static async cleanupExpiredSessions(): Promise<void> {
    try {
      await prisma.userSession.deleteMany({
        where: {
          expiresAt: {
            lt: new Date()
          }
        }
      })
    } catch (error) {
      console.error('清理过期会话失败:', error)
    }
  }

  // 简单的令牌哈希（实际项目中应使用更安全的哈希方法）
  private static hashToken(token: string): string {
    const crypto = require('crypto')
    return crypto.createHash('sha256').update(token).digest('hex')
  }

  // 获取令牌剩余时间
  static getTokenRemainingTime(token: string): number {
    const decoded = this.decodeToken(token)
    if (!decoded || !decoded.exp) return 0
    
    const now = Math.floor(Date.now() / 1000)
    return Math.max(0, decoded.exp - now)
  }

  // 检查令牌是否即将过期（5分钟内）
  static isTokenExpiringSoon(token: string): boolean {
    const remainingTime = this.getTokenRemainingTime(token)
    return remainingTime > 0 && remainingTime < 300 // 5分钟
  }
}

export default JWTManager